﻿using System;
using System.Collections.Generic;
using System.Linq;
using EntityFrameworkExtension.Interface;

namespace EntityFrameworkExtension.Caching
{

    public class DataCache : IDataCache 
    {
        private readonly List<Object> list;

        public DataCache()
        {
            list = new List<object>();
        }

        public List<T> GetTypeMapping<T>(IEfContext efContext) where T : class , IEquatable<T>
        {
            return GetTypeMapping<T>(efContext, NoReload);
        }

        public List<T> GetTypeMappingWithRefresh<T>(IEfContext efContext) where T : class , IEquatable<T>
        {
            return GetTypeMapping<T>(efContext, ReloadData<T>);
        }

        private static void NoReload<T>(IEfContext efContext, CacheableListOfData<T> concreteType)  where T : class , IEquatable<T>
        {
        }

        private static void ReloadData<T>(IEfContext efContext, CacheableListOfData<T> concreteType)  where T : class , IEquatable<T>
        {
            concreteType.ReloadData(efContext);
        }


        private List<T> GetTypeMapping<T>(IEfContext efContext, Action<IEfContext, CacheableListOfData<T>> action) where T : class , IEquatable<T>
        {
            var type = list.Find(x => x.GetType() == typeof(CacheableListOfData<T>));

            var concreteType = type == null ? AddNewTypeToList<T>() : type as CacheableListOfData<T>;

            if (concreteType != null)
            {
                action(efContext, concreteType);
                return concreteType.GetData(efContext);
            }
            return Enumerable.Empty<T>().ToList();
        }

        
        private CacheableListOfData<T> AddNewTypeToList<T>() where T : class , IEquatable<T>
        {
            var concreteType = new CacheableListOfData<T>(x => x.GetObjectList<T>().ToList());
            list.Add(concreteType);
            return concreteType;
        }


        public TU GetId<T, TU>(string name, IEfContext iefContext) where T : class ,IReferenceTypeMapping<TU>, IEquatable<T> where TU : struct
        {
            return (from x in GetTypeMapping<T>(iefContext)
                    where x.Name == name
                    select x.Id).FirstOrDefault();
        }

        public T GetObject<T, TU>(string name, IEfContext iefContext) where T : class, IReferenceTypeMapping<TU>, IEquatable<T> where TU : struct
        {
            return (from x in GetTypeMapping<T>(iefContext)
                    where x.Name == name
                    select x).FirstOrDefault();
        }
    }
}


